package com.netsdk.demo.customize;

import static com.netsdk.lib.Utils.getOsPrefix;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Objects;
import java.util.Scanner;


import com.netsdk.demo.customize.faceReconEx.DefaultFaceFindStateCallback;
import com.netsdk.demo.util.CaseMenu;
import com.netsdk.lib.NetSDKLib;
import com.netsdk.lib.ToolKits;
import com.netsdk.lib.NetSDKLib.DEV_EVENT_HUMANTRAIT_INFO;
import com.netsdk.lib.NetSDKLib.LLong;
import com.netsdk.lib.NetSDKLib.NET_GET_CHANNEL_INFO;
import com.netsdk.lib.NetSDKLib.NET_GET_DEVICE_INFO;
import com.netsdk.lib.NetSDKLib.NET_IN_FACE_RECOGNITION_DEL_DISPOSITION_INFO;
import com.netsdk.lib.NetSDKLib.NET_IN_FACE_RECOGNITION_PUT_DISPOSITION_INFO;
import com.netsdk.lib.NetSDKLib.NET_IN_GET_CHANNEL_INFO;
import com.netsdk.lib.NetSDKLib.NET_IN_GET_DEVICE_LIST_INFO;
import com.netsdk.lib.NetSDKLib.NET_IN_OPERATE_FACERECONGNITIONDB;
import com.netsdk.lib.NetSDKLib.NET_OUT_FACE_RECOGNITION_DEL_DISPOSITION_INFO;
import com.netsdk.lib.NetSDKLib.NET_OUT_FACE_RECOGNITION_PUT_DISPOSITION_INFO;
import com.netsdk.lib.NetSDKLib.NET_OUT_GET_CHANNEL_INFO;
import com.netsdk.lib.NetSDKLib.NET_OUT_GET_DEVICE_LIST_INFO;
import com.netsdk.lib.NetSDKLib.NET_OUT_OPERATE_FACERECONGNITIONDB;
import com.netsdk.lib.NetSDKLib.NET_TRAFFICCAR_BLACK_LIST;
import com.netsdk.lib.NetSDKLib.NET_UID_CHAR;
import com.netsdk.lib.callback.impl.DefaultDisconnectCallback;
import com.netsdk.lib.callback.impl.DefaultHaveReconnectCallBack;
import com.netsdk.lib.enumeration.EM_DETECT_OBJECT_TYPE;
import com.netsdk.lib.enumeration.EM_EVENT_IVS_TYPE;
import com.netsdk.lib.enumeration.EM_MULTIFACE_DETECT_ERRCODE;
import com.netsdk.lib.enumeration.EM_NEEDED_PIC_RETURN_TYPE;
import com.netsdk.lib.enumeration.EM_OBJECT_COLOR_TYPE;
import com.netsdk.lib.enumeration.ENUMERROR;
import com.netsdk.lib.structure.NET_CANDIDATE_INFOEX2;
import com.netsdk.lib.structure.NET_CB_MULTIFACE_DETECT_STATE;
import com.netsdk.lib.structure.NET_DEVICE_CHANNEL_INFO;
import com.netsdk.lib.structure.NET_GET_DEVICE_INFO_EX;
import com.netsdk.lib.structure.NET_IN_DOFIND_FACERECONGNITION_EX;
import com.netsdk.lib.structure.NET_IN_FACERSERVER_GETDETEVTTOKEN;
import com.netsdk.lib.structure.NET_IN_FACE_RECOGNITION_DETECT_MULTI_FACE_INFO;
import com.netsdk.lib.structure.NET_IN_GET_DEVICE_INFO_EX;
import com.netsdk.lib.structure.NET_IN_MULTIFACE_DETECT_STATE;
import com.netsdk.lib.structure.NET_IN_STARTMULTIFIND_FACERECONGNITION_EX;
import com.netsdk.lib.structure.NET_OUT_DOFIND_FACERECONGNITION_EX;
import com.netsdk.lib.structure.NET_OUT_FACERSERVER_GETDETEVTTOKEN;
import com.netsdk.lib.structure.NET_OUT_FACE_RECOGNITION_DETECT_MULTI_FACE_INFO;
import com.netsdk.lib.structure.NET_OUT_GET_DEVICE_INFO_EX;
import com.netsdk.lib.structure.NET_OUT_MULTIFACE_DETECT_STATE;
import com.netsdk.lib.structure.NET_OUT_STARTMULTIFIND_FACERECONGNITION_EX;
import com.netsdk.lib.structure.NET_SMALL_PIC_INFO;
import com.netsdk.module.AnalyseTaskModule;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;

public class MC8000Demo {
	// SDk对象初始化
	public static final NetSDKLib netsdk = NetSDKLib.NETSDK_INSTANCE;
	public static final NetSDKLib configsdk = NetSDKLib.CONFIG_INSTANCE;

	// 判断是否初始化
	private static boolean bInit = false;
	// 判断log是否打开
	private static boolean bLogOpen = false;
	// 设备信息
	private NetSDKLib.NET_DEVICEINFO_Ex deviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex();
	// 登录句柄
	private NetSDKLib.LLong m_hLoginHandle = new NetSDKLib.LLong(0);

	// 智能事件订阅句柄
	private NetSDKLib.LLong m_attachHandle = new NetSDKLib.LLong(0);

	// 回调函数需要是静态的，防止被系统回收
	// 断线回调
	private static NetSDKLib.fDisConnect disConnectCB = DefaultDisconnectCallback.getINSTANCE();
	// 重连回调
	private static NetSDKLib.fHaveReConnect haveReConnectCB = DefaultHaveReconnectCallBack.getINSTANCE();

	// 编码格式
	public static String encode;

	static {
		String osPrefix = getOsPrefix();
		if (osPrefix.toLowerCase().startsWith("win32-amd64")) {
			encode = "GBK";
		} else if (osPrefix.toLowerCase().startsWith("linux-amd64")) {
			encode = "UTF-8";
		}
	}

	/**
	 * 获取当前时间
	 */
	public static String GetDate() {
		SimpleDateFormat simpleDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		return simpleDate.format(new java.util.Date()).replaceAll("[^0-9]", "-");
	}

	/**
	 * 初始化SDK库
	 */
	public static boolean Init() {
		bInit = netsdk.CLIENT_Init(disConnectCB, null);// 进程启动时，初始化一次
		if (!bInit) {
			System.out.println("Initialize SDK failed");
			return false;
		}
		// 配置日志
		MC8000Demo.enableLog();

		// 设置断线重连回调接口, 此操作为可选操作，但建议用户进行设置
		netsdk.CLIENT_SetAutoReconnect(haveReConnectCB, null);

		// 设置登录超时时间和尝试次数，可选
		// 登录请求响应超时时间设置为3S
		int waitTime = 3000;
		// 登录时尝试建立链接 1 次
		int tryTimes = 1;
		netsdk.CLIENT_SetConnectTime(waitTime, tryTimes);
		// 设置更多网络参数， NET_PARAM 的nWaittime ， nConnectTryNum 成员与 CLIENT_SetConnectTime
		// 接口设置的登录设备超时时间和尝试次数意义相同,可选
		NetSDKLib.NET_PARAM netParam = new NetSDKLib.NET_PARAM();
		// 登录时尝试建立链接的超时时间
		netParam.nConnectTime = 10000;
		// 设置子连接的超时时间
		netParam.nGetConnInfoTime = 3000;
		netsdk.CLIENT_SetNetworkParam(netParam);
		return true;
	}

	/**
	 * 打开 sdk log
	 */
	private static void enableLog() {
		NetSDKLib.LOG_SET_PRINT_INFO setLog = new NetSDKLib.LOG_SET_PRINT_INFO();
		File path = new File("sdklog/");
		if (!path.exists())
			path.mkdir();

		// 这里的log保存地址依据实际情况自己调整
		String logPath = path.getAbsoluteFile().getParent() + "\\sdklog\\" + "sdklog" + GetDate() + ".log";
		setLog.nPrintStrategy = 0;
		setLog.bSetFilePath = 1;
		System.arraycopy(logPath.getBytes(), 0, setLog.szLogFilePath, 0, logPath.getBytes().length);
		System.out.println(logPath);
		setLog.bSetPrintStrategy = 1;
		bLogOpen = netsdk.CLIENT_LogOpen(setLog);
		if (!bLogOpen)
			System.err.println("Failed to open NetSDK log");
	}

	/**
	 * 高安全登录
	 */
	public void loginWithHighLevel() {
		// 输入结构体参数
		NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstlnParam = new NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY() {
			{
				szIP = m_strIpAddr.getBytes();
				nPort = m_nPort;
				szUserName = m_strUser.getBytes();
				szPassword = m_strPassword.getBytes();
			}
		};
		// 输出结构体参数
		NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam = new NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY();

		// 写入sdk
		m_hLoginHandle = netsdk.CLIENT_LoginWithHighLevelSecurity(pstlnParam, pstOutParam);
		if (m_hLoginHandle.longValue() == 0) {
			System.err.printf("Login Device[%s] Port[%d]Failed. %s\n", m_strIpAddr, m_nPort,
					netsdk.CLIENT_GetLastError());
		} else {
			deviceInfo = pstOutParam.stuDeviceInfo; // 获取设备信息
			System.out.println("Login Success");
			System.out.println("Device Address：" + m_strIpAddr);
			System.out.println("设备包含：" + deviceInfo.byChanNum + "个通道");
		}
	}

	/**
	 * 退出
	 */
	public void logOut() {
		if (m_hLoginHandle.longValue() != 0) {
			netsdk.CLIENT_Logout(m_hLoginHandle);
			System.out.println("LogOut Success");
		}
	}

	/**
	 * 清理sdk环境并退出
	 */
	public static void cleanAndExit() {
		if (bLogOpen) {
			netsdk.CLIENT_LogClose(); // 关闭sdk日志打印
		}
		netsdk.CLIENT_Cleanup(); // 进程关闭时，调用一次
		System.exit(0);
	}

	/**
	 * 选择通道
	 */
	private int channelId = -1;// 逻辑通道

	public void setChannelID() {
		System.out.println("请输入通道，从0开始计数，-1表示全部");
		Scanner sc = new Scanner(System.in);
		this.channelId = sc.nextInt();
	}

	/**
	 * 订阅智能任务
	 */
	public void AttachEventRealLoadPic() {
		// 先退订，设备不会对重复订阅作校验，重复订阅后会有重复的事件返回
		this.DetachEventRealLoadPic();
		// 需要图片
		int bNeedPicture = 1;
		m_attachHandle = netsdk.CLIENT_RealLoadPictureEx(m_hLoginHandle, channelId, NetSDKLib.EVENT_IVS_ALL,
				bNeedPicture, AnalyzerDataCB.getInstance(), null, null);
		if (m_attachHandle.longValue() != 0) {
			System.out.printf("Chn[%d] CLIENT_RealLoadPictureEx Success\n", channelId);
		} else {
			System.out.printf("Ch[%d] CLIENT_RealLoadPictureEx Failed!LastError = %s\n", channelId,
					ToolKits.getErrorCode());
		}
	}

	/**
	 * 报警事件（智能）回调
	 */
	private static class AnalyzerDataCB implements NetSDKLib.fAnalyzerDataCallBack {
		private final File picturePath;
		private static AnalyzerDataCB instance;

		private AnalyzerDataCB() {
			picturePath = new File("./AnalyzerPicture/");
			if (!picturePath.exists()) {
				picturePath.mkdirs();
			}
		}

		public static AnalyzerDataCB getInstance() {
			if (instance == null) {
				instance = new AnalyzerDataCB();
			}
			return instance;
		}

		@Override
		public int invoke(LLong m_attachHandle, int dwAlarmType, Pointer pAlarmInfo, Pointer pBuffer, int dwBufSize,
				Pointer dwUser, int nSequence, Pointer reserved) {
			/**
			 * 回调函数使用注意（防止卡回调） 1.不能再回调进行耗时操作，建议将数据、图片流、视频流等通过中间件和多线程抛出处理
			 * 2.不能再回调调用netsdk的其他接口
			 */
			if (m_attachHandle == null || m_attachHandle.longValue() == 0) {
				return -1;
			}

			switch (Objects.requireNonNull(EM_EVENT_IVS_TYPE.getEventType(dwAlarmType))) {
			case EVENT_IVS_FACEDETECT: { // 人脸检测事件(对应 DEV_EVENT_FACEDETECT_INFO)
				System.out.println("人脸检测事件----------------");
				NetSDKLib.DEV_EVENT_FACEDETECT_INFO msg = new NetSDKLib.DEV_EVENT_FACEDETECT_INFO();
				ToolKits.GetPointerData(pAlarmInfo, msg);
				int nPresetID = msg.stuIntelliCommInfo.nPresetID;
				System.out.println("nPresetID : " + nPresetID);
				break;
			}
			case EVENT_IVS_FACERECOGNITION: {// 目标识别事件(对应 DEV_EVENT_FACERECOGNITION_INFO)
				System.out.println("目标识别事件----------------");
				// 该智能事件结构体较大，提升性能可以参考TargetRecognitionExDemo，在初始化前调用CLIENT_SetIVSEventParseType指定结构体
				// DEV_EVENT_FACERECOGNITION_INFO_V1
				NetSDKLib.DEV_EVENT_FACERECOGNITION_INFO msg = new NetSDKLib.DEV_EVENT_FACERECOGNITION_INFO();
				ToolKits.GetPointerData(pAlarmInfo, msg);
				System.out.println("szName : " + new String(msg.szName).trim() + "\n");
				System.out.println("时间(UTC):" + msg.UTC);

				/////////////// 保存全景图 ///////////////////
				if (msg.bGlobalScenePic == 1 && msg.stuGlobalScenePicInfo != null) {
					String bigPicture = picturePath + "\\" + "Global" + System.currentTimeMillis() + ".jpg";
					//ToolKits.savePicture(pBuffer, msg.stuGlobalScenePicInfo.dwOffSet,
					//msg.stuGlobalScenePicInfo.dwFileLenth, bigPicture);
				}
				break;
			}
			case EVENT_IVS_HUMANTRAIT: {// 人体特征事件(对应 DEV_EVENT_HUMANTRAIT_INFO)
				System.out.println("人体特征事件------------");
				DEV_EVENT_HUMANTRAIT_INFO msg = new DEV_EVENT_HUMANTRAIT_INFO();
				ToolKits.GetPointerData(pAlarmInfo, msg);				
				System.out.println("通道号: "+msg.nChannelID);
                //帽子类型
                switch (msg.stuHumanAttributes.emCap) {
                    case 0:
                        System.out.println("未知");
                        break;

                    case 1:
                        System.out.println("普通帽子");
                        break;

                    case 2:
                        System.out.println("头盔");
                        break;
                    case 3:
                        System.out.println("安全帽");
                        break;

                    default:
                        System.out.println("未知");
                        break;
                }
																
				// 保存全景图片
				if (msg.stuSceneImage.nLength > 0) {
					String strFileName = picturePath + "\\" + System.currentTimeMillis() + "HumanTrait_全景图.jpg";
					// ToolKits.savePicture(pBuffer, msg.stuSceneImage.nOffSet,
					// msg.stuSceneImage.nLength, strFileName);
				} else {
					System.out.println("无全景图");
				}

				// 保存人脸图
				if (msg.stuFaceImage.nLength > 0) {
					String strFileName = picturePath + "\\" + System.currentTimeMillis() + "HumanTrait_人脸图.jpg";
					// ToolKits.savePicture(pBuffer, msg.stuFaceImage.nOffSet,
					// msg.stuFaceImage.nLength, strFileName);
				} else {
					System.out.println("无人脸图");
				}

				// 保存人脸全景图
				if (msg.stuFaceSceneImage.nLength > 0) {
					String strFileName = picturePath + "\\" + System.currentTimeMillis() + "HumanTrait_人脸全景图.jpg";
					// ToolKits.savePicture(pBuffer, msg.stuFaceSceneImage.nOffSet,
					// msg.stuFaceSceneImage.nLength, strFileName);
				} else {
					System.out.println("无人脸全景图");
				}

				// 保存人体图
				if (msg.stuHumanImage.nLength > 0) {
					String strFileName = picturePath + "\\" + System.currentTimeMillis() + "HumanTrait_人体图.jpg";
					// ToolKits.savePicture(pBuffer, msg.stuHumanImage.nOffSet,
					// msg.stuHumanImage.nLength, strFileName);
				} else {
					System.out.println("无人体图");
				}
				break;
			}
			case EVENT_IVS_TRAFFICJUNCTION: {// 交通路口事件(对应 DEV_EVENT_TRAFFICJUNCTION_INFO)
				System.out.println("交通路口事件------------");
				// 路口事件，抓拍车牌
				NetSDKLib.DEV_EVENT_TRAFFICJUNCTION_INFO trafficJunction = new NetSDKLib.DEV_EVENT_TRAFFICJUNCTION_INFO();
				// 获取车牌信息
				ToolKits.GetPointerDataToStruct(pAlarmInfo, 0, trafficJunction);
				String date = trafficJunction.UTC.toStringTime();
				NetSDKLib.DEV_EVENT_TRAFFIC_TRAFFICCAR_INFO trafficCar = trafficJunction.stTrafficCar;
				try {
					System.out.println(date + " traffic number:" + new String(trafficCar.szPlateNumber, encode)
							+ ",plate color:" + new String(trafficCar.szPlateColor, encode));
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
				System.out.println("emVehicleTypeByFunc = " + trafficJunction.stTrafficCar.emVehicleTypeByFunc);
				System.out.println("nSunBrand = " + trafficJunction.stTrafficCar.nSunBrand);
				System.out.println("nBrandYear = " + trafficJunction.stTrafficCar.nBrandYear);

				// save the picture
				String imageName = "trafficJunction_" + trafficJunction.UTC.toStringTitle() + ".jpg";
				String savePath = picturePath + "/" + imageName;
				ToolKits.savePicture(pBuffer, dwBufSize, savePath);
				System.out.println("save picture to " + savePath);
				NET_TRAFFICCAR_BLACK_LIST stuBlackList = trafficCar.stuBlackList;
				int nControlledRouteID = stuBlackList.nControlledRouteID;
				System.out.println("nControlledRouteID = " + nControlledRouteID);
				break;

			}
			default:
				// System.out.println("其他事件--------------------"+ dwAlarmType);
				break;
			}
			return 0;
		}
	}

	/**
	 * 停止侦听智能事件
	 */
	public void DetachEventRealLoadPic() {
		if (m_attachHandle.longValue() != 0) {
			netsdk.CLIENT_StopLoadPic(m_attachHandle);
		}
	}

	/**
	 * 获取已添加的设备信息
	 */
	public boolean getAllDeviceInfo() {
		String[] deviceIDs = null;// 设备id列表为空，默认查全部
		// String[] deviceIDs = { "CXbGbmlFA1E8GQ7A6P1C9R" };
		return getDeviceInfo(deviceIDs);
	}

	public boolean getDeviceInfo(String[] deviceIDs) { // 获取已添加的设备信息
		NET_IN_GET_DEVICE_LIST_INFO pstInParam = new NET_IN_GET_DEVICE_LIST_INFO();
		NET_OUT_GET_DEVICE_LIST_INFO pstOutParam = new NET_OUT_GET_DEVICE_LIST_INFO();

		if (deviceIDs != null) {
			pstInParam.nCount = deviceIDs.length;
			for (int i = 0; i < pstInParam.nCount; i++) {
				System.arraycopy(deviceIDs[i].getBytes(), 0, pstInParam.szDeviceIDsArr[i].szDeviceID, 0,
						deviceIDs[i].getBytes().length);
			}
			pstOutParam.nMaxCount = pstInParam.nCount;
		} else {
			pstInParam.nCount = 0;
			pstOutParam.nMaxCount = NetSDKLib.MAX_LINK_DEVICE_NUM;
		}

		NET_GET_DEVICE_INFO[] deviceInfo = new NET_GET_DEVICE_INFO[pstOutParam.nMaxCount];
		for (int i = 0; i < pstOutParam.nMaxCount; i++) {
			deviceInfo[i] = new NET_GET_DEVICE_INFO();
		}
		pstOutParam.pstuDeviceInfo = new Memory(deviceInfo[0].size() * pstOutParam.nMaxCount);
		pstOutParam.pstuDeviceInfo.clear(deviceInfo[0].size() * pstOutParam.nMaxCount);
		ToolKits.SetStructArrToPointerData(deviceInfo, pstOutParam.pstuDeviceInfo); // 将数组内存拷贝到Pointer

		boolean bRet = netsdk.CLIENT_GetDeviceInfo(m_hLoginHandle, pstInParam, pstOutParam, 3000);
		if (!bRet) {
			System.err.printf("GetDeviceInfo Fail.Last Error[0x%x]\n", netsdk.CLIENT_GetLastError());
			return false;
		}

		ToolKits.GetPointerDataToStructArr(pstOutParam.pstuDeviceInfo, deviceInfo); // 将 Pointer 的内容 输出到 数组
		for (int i = 0; i < pstOutParam.nRetCount; i++) {
			System.out.println("设备ID:" + new String(deviceInfo[i].szDeviceID).trim());
			System.out.println("url:" + new String(deviceInfo[i].szUrl).trim());
			System.out.println("设备序列号:" + new String(deviceInfo[i].szSerialNo).trim());
			System.out.println("设备类型:" + new String(deviceInfo[i].szDeviceType).trim());
			System.out.println();
		}
		return true;
	}

	/**
	 * 获取设备通道信息
	 * 
	 */
	public void getChannelInfo() {
		String deviceID = "7gC9c4470457t0V7P4434N";
		NET_IN_GET_CHANNEL_INFO pstInParam = new NET_IN_GET_CHANNEL_INFO();
		System.arraycopy(deviceID.getBytes(), 0, pstInParam.szDeviceID, 0, deviceID.getBytes().length);

		NET_GET_CHANNEL_INFO[] channelInfo = new NET_GET_CHANNEL_INFO[NetSDKLib.MAX_DEVICE_CHANNEL_NUM];
		for (int i = 0; i < channelInfo.length; i++) {
			channelInfo[i] = new NET_GET_CHANNEL_INFO();
		}

		NET_OUT_GET_CHANNEL_INFO pstOutParam = new NET_OUT_GET_CHANNEL_INFO();
		pstOutParam.nMaxCount = channelInfo.length; // 用户申请的通道个数
		pstOutParam.pstuChannelInfo = new Memory(channelInfo[0].size() * pstOutParam.nMaxCount);
		pstOutParam.pstuChannelInfo.clear(channelInfo[0].size() * pstOutParam.nMaxCount);
		ToolKits.SetStructArrToPointerData(channelInfo, pstOutParam.pstuChannelInfo); // 将数组内存拷贝到Pointer

		boolean bRet = netsdk.CLIENT_GetChannelInfo(m_hLoginHandle, pstInParam, pstOutParam, 3000);
		if (!bRet) {
			System.err.printf("GetChannelInfo Fail.Last Error[0x%x]\n", netsdk.CLIENT_GetLastError());
			return;
		}
		ToolKits.GetPointerDataToStructArr(pstOutParam.pstuChannelInfo, channelInfo);// 将 Pointer 的内容 输出到 数组
		System.out.println("用户申请的通道个数:" + pstOutParam.nMaxCount);
		System.out.println("实际返回的通道个数:" + pstOutParam.nRetCount);
		try {
			for (int i = 0; i < pstOutParam.nRetCount; i++) {
				System.out.println("--------获取设备通道信息结果信息---------");
				System.out.println("远程通道号:" + channelInfo[i].nRemoteChannel);
				System.out.println("分配的逻辑通道,-1表示未分配:" + channelInfo[i].nLogicChannel);
				System.out.println("通道名称:" + new String(channelInfo[i].szName, encode));
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 设备、通道信息一起获取
	 * 
	 * @throws UnsupportedEncodingException
	 */
	public void getDeviceInfoEx() throws UnsupportedEncodingException {
		String[] deviceIDs = null;// 设备id列表为空，默认查全部,数据返回太慢，性能较差不建议使用
		// String[] deviceIDs = { "CXbGbmlFA1EL8TPM4LVDFP","7gC9c4470457t0V7P4434N" };
		getDeviceInfoExDo(deviceIDs);
	}

	public void getDeviceInfoExDo(String[] deviceIDsArr) throws UnsupportedEncodingException {
		// 入参
		NET_IN_GET_DEVICE_INFO_EX pstInParam = new NET_IN_GET_DEVICE_INFO_EX();
		// 出参
		NET_OUT_GET_DEVICE_INFO_EX pstOutParam = new NET_OUT_GET_DEVICE_INFO_EX();
		String[] deviceIDs = deviceIDsArr;
		if (deviceIDs != null) {
			pstInParam.nCount = deviceIDs.length;// 长度不能大于32
			for (int i = 0; i < pstInParam.nCount; i++) {
				System.arraycopy(deviceIDs[i].getBytes(), 0, pstInParam.szDeviceIDs[i].szDeviceID, 0,
						deviceIDs[i].getBytes().length);
			}
			pstOutParam.nMaxCount = deviceIDs.length; // 用户申请的通道个数
		} else {
			pstInParam.nCount = 0;
			pstOutParam.nMaxCount = NetSDKLib.MAX_LINK_DEVICE_NUM;
		}
		pstInParam.write();

		// 初始化通道信息
		// int nMaxChannelCount = NetSDKLib.MAX_DEVICE_CHANNEL_NUM;
		int nMaxChannelCount = 10;// 每个设备用户申请的通道个数
		NET_DEVICE_CHANNEL_INFO[] channalInfo = new NET_DEVICE_CHANNEL_INFO[nMaxChannelCount];
		for (int i = 0; i < channalInfo.length; i++) {
			channalInfo[i] = new NET_DEVICE_CHANNEL_INFO();
		}

		// 初始化设备的结果信息
		NET_GET_DEVICE_INFO_EX[] deviceInfo = new NET_GET_DEVICE_INFO_EX[pstOutParam.nMaxCount];
		for (int i = 0; i < deviceInfo.length; i++) {
			NET_GET_DEVICE_INFO_EX info = new NET_GET_DEVICE_INFO_EX();
			info.nMaxChannelCount = nMaxChannelCount; // 每个设备用户申请的通道个数
			info.pstuChannelsInfo = new Memory(channalInfo[0].size() * nMaxChannelCount);
			info.pstuChannelsInfo.clear(channalInfo[0].size() * nMaxChannelCount);
			// 将数组内存拷贝到Pointer
			ToolKits.SetStructArrToPointerData(channalInfo, info.pstuChannelsInfo);
			deviceInfo[i] = info;
		}

		pstOutParam.nMaxCount = pstOutParam.nMaxCount; // 用户申请的通道个数
		pstOutParam.pstuDeviceInfo = new Memory(deviceInfo[0].size() * pstOutParam.nMaxCount);
		pstOutParam.pstuDeviceInfo.clear(deviceInfo[0].size() * pstOutParam.nMaxCount);
		ToolKits.SetStructArrToPointerData(deviceInfo, pstOutParam.pstuDeviceInfo); // 将数组内存拷贝到Pointer
		pstOutParam.write();
		boolean flg = netsdk.CLIENT_GetDeviceInfoEx(m_hLoginHandle, pstInParam.getPointer(), pstOutParam.getPointer(),
				4000);
		pstInParam.read();
		if (flg) {
			System.out.println("CLIENT_GetDeviceInfoEx Succeed!");
			pstOutParam.read();
			System.out.println("实际返回的设备个数: " + pstOutParam.nRetCount);
			ToolKits.GetPointerDataToStructArr(pstOutParam.pstuDeviceInfo, deviceInfo); // 将 Pointer 的内容 输出到 数组
			for (int i = 0; i < pstOutParam.nRetCount; i++) {
				System.out.println("第" + (i + 1) + "设备信息------------------");
				System.out.println("设备ID:" + new String(deviceInfo[i].szDeviceID).trim());
				System.out.println("url:" + new String(deviceInfo[i].szUrl).trim());
				System.out.println("设备序列号:" + new String(deviceInfo[i].szSerialNo).trim());
				System.out.println("设备类型:" + new String(deviceInfo[i].szDeviceType).trim());
				System.out.println();
				System.out.println("用户申请的通道个数: " + deviceInfo[i].nMaxChannelCount);
				System.out.println("实际返回的通道个数: " + deviceInfo[i].nRetChannelCount);
				ToolKits.GetPointerDataToStructArr(deviceInfo[i].pstuChannelsInfo, channalInfo);
				for (int j = 0; j < deviceInfo[i].nRetChannelCount; j++) {
					System.out.println("第" + (j + 1) + "通道信息---------");
					System.out.println("远程通道号:" + channalInfo[j].nRemoteChannel);
					System.out.println("分配的逻辑通道,-1表示未分配:" + channalInfo[j].nLogicChannel);
					System.out.println("通道名称:" + new String(channalInfo[j].szName, encode));
				}
			}

		} else {
			System.out.println("CLIENT_GetDeviceInfoEx Failed, Error:" + ToolKits.getErrorCode());
		}

	}

	private int nToken;

	/**
	 * 获取检测Token
	 */
	public void faceRServerGetDetectToken() {
		// 入参
		NET_IN_FACERSERVER_GETDETEVTTOKEN pstInParam = new NET_IN_FACERSERVER_GETDETEVTTOKEN();
		pstInParam.write();
		// 出参
		NET_OUT_FACERSERVER_GETDETEVTTOKEN pstOutParam = new NET_OUT_FACERSERVER_GETDETEVTTOKEN();
		pstOutParam.write();
		boolean flg = netsdk.CLIENT_FaceRServerGetDetectToken(m_hLoginHandle, pstInParam.getPointer(),
				pstOutParam.getPointer(), 4000);
		pstInParam.read();
		pstOutParam.read();
		if (flg) {
			System.out.println("faceRServerGetDetectToken Succeed!");
			System.out.println("获取到的查询令牌: " + pstOutParam.nToken);
			nToken = pstOutParam.nToken;
		} else {
			System.out.println("faceRServerGetDetectToken Failed, Error:" + ToolKits.getErrorCode());
		}
	}

	private NetSDKLib.LLong attachFaceHandle = new NetSDKLib.LLong(0);


	
	
	/**
	 * 查询人脸库信息
	 */
	public void findGroupInfo() {
		// groupId 需要查找的人脸库ID; 为空表示查找所有的人脸库
		//String groupId = "1";
		String groupId = "";
		// 入参
		NetSDKLib.NET_IN_FIND_GROUP_INFO stIn = new NetSDKLib.NET_IN_FIND_GROUP_INFO();
		System.arraycopy(groupId.getBytes(), 0, stIn.szGroupId, 0, groupId.getBytes().length);

		// 出参
		int max = 20;
		NetSDKLib.NET_FACERECONGNITION_GROUP_INFO[] groupInfo = new NetSDKLib.NET_FACERECONGNITION_GROUP_INFO[max];
		for (int i = 0; i < max; i++) {
			groupInfo[i] = new NetSDKLib.NET_FACERECONGNITION_GROUP_INFO();
		}

		NetSDKLib.NET_OUT_FIND_GROUP_INFO stOut = new NetSDKLib.NET_OUT_FIND_GROUP_INFO();
		stOut.pGroupInfos = new Memory(groupInfo[0].size() * 20); // Pointer初始化
		stOut.pGroupInfos.clear(groupInfo[0].size() * 20);
		stOut.nMaxGroupNum = max;

		ToolKits.SetStructArrToPointerData(groupInfo, stOut.pGroupInfos); // 将数组内存拷贝给Pointer

		if (netsdk.CLIENT_FindGroupInfo(m_hLoginHandle, stIn, stOut, 4000)) {
			ToolKits.GetPointerDataToStructArr(stOut.pGroupInfos, groupInfo); // 将Pointer的值输出到数组NET_FACERECONGNITION_GROUP_INFO
			System.out.println("FindGroupInfo successful,num:"+stOut.nRetGroupNum);
			for (int i = 0; i < stOut.nRetGroupNum; i++) {
				// 人脸库ID
				System.out.println("[" + i + "]szGroupId: " + new String(groupInfo[i].szGroupId).trim());
				// 人脸库名称
				try {
					System.out.println("[" + i + "]szGroupName: " + new String(groupInfo[i].szGroupName, encode).trim());
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
				// 相似度
				String nSimilarityCount = "";
				for (int j = 0; j < groupInfo[i].nRetSimilarityCount; j++) {
					nSimilarityCount = nSimilarityCount + "  " + String.valueOf(groupInfo[i].nSimilarity[j]);
				}
				System.out.println("[" + i + "]nSimilarityCount: " + nSimilarityCount);
				// 当前组绑定到的视频通道号列表
				String nChannelCount = "";
				for (int j = 0; j < groupInfo[i].nRetChnCount; j++) {
					nChannelCount = nChannelCount + "  " + String.valueOf(groupInfo[i].nChannel[j]);
				}
				System.out.println("[" + i + "]nChannelCount: " + nChannelCount);
				// 人员组备注信息
				System.out.println("[" + i + "]szGroupRemarks: " + new String(groupInfo[i].szGroupRemarks).trim());
				// 当前组内人员数
				System.out.println("[" + i + "]nGroupSize: " + groupInfo[i].nGroupSize);
				// 人员组类型,详见EM_FACE_DB_TYPE, 取值为EM_FACE_DB_TYPE中的值
				System.out.println("[" + i + "]emFaceDBType: " + groupInfo[i].emFaceDBType);
			}
		} else {
			System.err.println("查询人员信息失败" + ToolKits.getErrorCode());
		}
	}
	
	/**
	 * 添加人脸库
	 */
	public boolean addFaceRecognitionGroup() {

		String groupName = "禁止名单数据库1";

		NetSDKLib.NET_ADD_FACERECONGNITION_GROUP_INFO addGroupInfo = new NetSDKLib.NET_ADD_FACERECONGNITION_GROUP_INFO();
		try {
			System.arraycopy(groupName.getBytes(encode), 0, addGroupInfo.stuGroupInfo.szGroupName, 0,
					groupName.getBytes(encode).length);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		addGroupInfo.stuGroupInfo.emFaceDBType = NetSDKLib.EM_FACE_DB_TYPE.NET_FACE_DB_TYPE_BLACKLIST;//禁止名单数据库

		// 入参
		NetSDKLib.NET_IN_OPERATE_FACERECONGNITION_GROUP stIn = new NetSDKLib.NET_IN_OPERATE_FACERECONGNITION_GROUP();
		stIn.emOperateType = NetSDKLib.EM_OPERATE_FACERECONGNITION_GROUP_TYPE.NET_FACERECONGNITION_GROUP_ADD; // 添加人员组信息
		stIn.pOPerateInfo = addGroupInfo.getPointer();

		// 出参
		NetSDKLib.NET_OUT_OPERATE_FACERECONGNITION_GROUP stOut = new NetSDKLib.NET_OUT_OPERATE_FACERECONGNITION_GROUP();

		addGroupInfo.write();
		boolean bRet = netsdk.CLIENT_OperateFaceRecognitionGroup(m_hLoginHandle, stIn, stOut, 4000);
		addGroupInfo.read();

		if (bRet) {
			System.out.println("人员组ID : " + new String(stOut.szGroupId).trim()); // 新增记录的人员组ID,唯一标识一组人员
			System.out.println("添加人脸库成功");
		} else {
			System.out.println("添加人脸库失败：" + ToolKits.getErrorCode());
			return false;
		}

		return true;
	}

	/**
	 * 修改人脸库
	 */
	public boolean modifyFaceRecognitionGroup() {
		String groupName = "禁止名单数据库";
		String groupId = "3";

		NetSDKLib.NET_MODIFY_FACERECONGNITION_GROUP_INFO modifyGroupInfo = new NetSDKLib.NET_MODIFY_FACERECONGNITION_GROUP_INFO();
		try {
			System.arraycopy(groupName.getBytes(encode), 0, modifyGroupInfo.stuGroupInfo.szGroupName, 0,
					groupName.getBytes(encode).length);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		System.arraycopy(groupId.getBytes(), 0, modifyGroupInfo.stuGroupInfo.szGroupId, 0, groupId.getBytes().length); // 给人员组ID赋值，要用数组拷贝
		modifyGroupInfo.stuGroupInfo.emFaceDBType = NetSDKLib.EM_FACE_DB_TYPE.NET_FACE_DB_TYPE_BLACKLIST;//禁止名单数据库
		// 入参
		NetSDKLib.NET_IN_OPERATE_FACERECONGNITION_GROUP stIn = new NetSDKLib.NET_IN_OPERATE_FACERECONGNITION_GROUP();
		stIn.emOperateType = NetSDKLib.EM_OPERATE_FACERECONGNITION_GROUP_TYPE.NET_FACERECONGNITION_GROUP_MODIFY; // 修改人员组信息
		stIn.pOPerateInfo = modifyGroupInfo.getPointer();

		// 出参
		NetSDKLib.NET_OUT_OPERATE_FACERECONGNITION_GROUP stOut = new NetSDKLib.NET_OUT_OPERATE_FACERECONGNITION_GROUP();

		modifyGroupInfo.write();
		boolean bRet = netsdk.CLIENT_OperateFaceRecognitionGroup(m_hLoginHandle, stIn, stOut, 4000);
		modifyGroupInfo.read();

		if (bRet) {
			System.out.println("修改人脸库成功");
		} else {
			System.out.println("修改人脸库失败：" + ToolKits.getErrorCode());
			return false;
		}

		return true;
	}

	/**
	 * 删除人脸库
	 */
	public boolean deleteFaceRecognitionGroup() {
		String groupId = "3";
		NetSDKLib.NET_DELETE_FACERECONGNITION_GROUP_INFO deleteGroupInfo = new NetSDKLib.NET_DELETE_FACERECONGNITION_GROUP_INFO();
		System.arraycopy(groupId.getBytes(), 0, deleteGroupInfo.szGroupId, 0, groupId.getBytes().length); // 给人员组ID赋值，要用数组拷贝

		// 入参
		NetSDKLib.NET_IN_OPERATE_FACERECONGNITION_GROUP stIn = new NetSDKLib.NET_IN_OPERATE_FACERECONGNITION_GROUP();
		stIn.emOperateType = NetSDKLib.EM_OPERATE_FACERECONGNITION_GROUP_TYPE.NET_FACERECONGNITION_GROUP_DELETE; // 删除人员组信息
		stIn.pOPerateInfo = deleteGroupInfo.getPointer();

		// 出参
		NetSDKLib.NET_OUT_OPERATE_FACERECONGNITION_GROUP stOut = new NetSDKLib.NET_OUT_OPERATE_FACERECONGNITION_GROUP();

		deleteGroupInfo.write();
		boolean bRet = netsdk.CLIENT_OperateFaceRecognitionGroup(m_hLoginHandle, stIn, stOut, 4000);
		deleteGroupInfo.read();

		if (bRet) {
			System.out.println("删除人脸库成功!");
		} else {
			System.out.println("删除人脸库失败：" + ToolKits.getErrorCode());
			return false;
		}

		return true;
	}
	

	

	/**
	 * 添加人员信息(即注册人脸)
	 * @param groupId 组ID(人脸库ID) 
	 * @param nPicBufLen 图片大小
	 * @param width 图片宽
	 * @param height 图片高 
	 * @param memory  保存图片的缓存
	 * @param personName 人员名称
	 * @param bySex 性别
	 * @param birthday 生日(年月日数组)
	 * @param province 省份
	 * @param id 证件编号
	 * @param byIdType 证件类型
	 */
	public boolean addFaceRecognitionDB() {				
		
		// 入参
		NET_IN_OPERATE_FACERECONGNITIONDB stuIn  = new NET_IN_OPERATE_FACERECONGNITIONDB();
		stuIn.emOperateType = NetSDKLib.EM_OPERATE_FACERECONGNITIONDB_TYPE.NET_FACERECONGNITIONDB_ADD;
		
		///////// 使用人员扩展信息 //////////
		stuIn.bUsePersonInfoEx = 1;   
		
		// 组ID设置
		String groupId = "3";
		System.arraycopy(groupId.getBytes(), 0, stuIn.stPersonInfoEx.szGroupID, 0, groupId.getBytes().length);
		
		// 生日设置
		String[] birthday = {"2000","7","26"};
		stuIn.stPersonInfoEx.wYear = (short)Integer.parseInt(birthday[0]);
		stuIn.stPersonInfoEx.byMonth = (byte)Integer.parseInt(birthday[1]);
		stuIn.stPersonInfoEx.byDay = (byte)Integer.parseInt(birthday[2]);
		
		// 性别,1-男,2-女,作为查询条件时,此参数填0,则表示此参数无效	
		byte bySex = 1;
		stuIn.stPersonInfoEx.bySex = bySex;	
		
		// 人员名字	
		String personName = "张生1";
		try {
			System.arraycopy(personName.getBytes(encode), 0, stuIn.stPersonInfoEx.szPersonName, 0, personName.getBytes(encode).length);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} 
		
		// 证件类型,详见 EM_CERTIFICATE_TYPE
		byte byIdType = 1;
		stuIn.stPersonInfoEx.byIDType = byIdType;  
		
		// 人员唯一标识(证件号码,工号,或其他编号)
		String id ="629006200017264513";
		System.arraycopy(id.getBytes(), 0, stuIn.stPersonInfoEx.szID, 0, id.getBytes().length); 					  
		
		// 国际,符合ISO3166规范
		System.arraycopy("CN".getBytes(), 0, stuIn.stPersonInfoEx.szCountry, 0, "CN".getBytes().length);	
		
		// 省份
		String province = "HB";
		try {
			System.arraycopy(province.getBytes(encode), 0, stuIn.stPersonInfoEx.szProvince, 0, province.getBytes(encode).length);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}  
		
		 // 城市
		String city = "WH";
		try {
			System.arraycopy(city.getBytes(encode), 0, stuIn.stPersonInfoEx.szCity, 0, city.getBytes(encode).length);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}  

	    // 当前接口的文件大小为int，这里进行强制转换，
	    // 意味着只能支持2G以下的文件
		String selectImagePath ="D:\\297.jpg";
		int nPicBufLen = (int)ToolKits.GetFileSize(selectImagePath);   // 图片大小
		// 读取文件大小失败
		if (nPicBufLen <= 0) {
			System.out.println("读取图片大小失败");
            return false;
		}
		Memory memory = new Memory(nPicBufLen);   // 申请缓存
		memory.clear();		
		if (!ToolKits.ReadAllFileToMemory(selectImagePath, memory)) {
        	System.out.printf("read all file from %s to memory failed!!!\n");
            return false;
		}				
		
		// 图片张数、大小、宽、高、缓存设置
		if(memory != null) {
			stuIn.stPersonInfoEx.wFacePicNum = 1; // 图片张数
			// 图片是否算法检测出来的检测过的提交识别服务器时,
            // 则不需要再时检测定位抠图,1:检测过的,0:没有检测过
			stuIn.stPersonInfo.szFacePicInfo[0].bIsDetected = 0;
			stuIn.stPersonInfoEx.szFacePicInfo[0].dwOffSet = 0;
			stuIn.stPersonInfoEx.szFacePicInfo[0].dwFileLenth = nPicBufLen;
			//stuIn.stPersonInfoEx.szFacePicInfo[0].wWidth = (short)0;
			//stuIn.stPersonInfoEx.szFacePicInfo[0].wHeight = (short)0;			
			stuIn.nBufferLen = nPicBufLen;
			stuIn.pBuffer = memory;
		}
		
		// 出参
		NET_OUT_OPERATE_FACERECONGNITIONDB stuOut = new NET_OUT_OPERATE_FACERECONGNITIONDB() ;	
		
		stuIn.write();
	    if(netsdk.CLIENT_OperateFaceRecognitionDB(m_hLoginHandle, stuIn, stuOut, 3000)) {
	    	System.out.println("添加人员信息成功!");
		} else {
			System.out.println("添加人员信息失败!"+ ToolKits.getErrorCode());
	    	return false;
	    }
	    stuIn.read();
	    System.out.println("人员唯一标识符szUID: "+new String(stuOut.szUID).trim());//000011692235373649020050150005

		return true;
	}
	
	/**
	 * 修改人员信息(即注册人脸)
	 * @param groupId 组ID(人脸库ID) 
	 * @param szUID 人员唯一标识符
	 * @param nPicBufLen 图片大小
	 * @param width 图片宽
	 * @param height 图片高 
	 * @param memory  保存图片的缓存
	 * @param personName 人员名称
	 * @param bySex 性别
	 * @param birthday 生日(年月日数组)
	 * @param province 省份
	 * @param id 证件编号
	 * @param byIdType 证件类型
	 */
	public boolean modifyFaceRecognitionDB() {
		// 入参
		NET_IN_OPERATE_FACERECONGNITIONDB stuIn  = new NET_IN_OPERATE_FACERECONGNITIONDB();
		stuIn.emOperateType = NetSDKLib.EM_OPERATE_FACERECONGNITIONDB_TYPE.NET_FACERECONGNITIONDB_MODIFY;
		
		///////// 使用人员扩展信息  ////////
		stuIn.bUsePersonInfoEx = 1;	
		
		// 组ID设置
		String groupId = "1";
		System.arraycopy(groupId.getBytes(), 0, stuIn.stPersonInfoEx.szGroupID, 0, groupId.getBytes().length);
		
		// UID设置
		String szUID = "000011692252252515025540162542";
		System.arraycopy(szUID.getBytes(), 0, stuIn.stPersonInfoEx.szUID, 0, szUID.getBytes().length); 
		
		// 生日设置
		String[] birthday = {"2001","7","26"};
		stuIn.stPersonInfoEx.wYear = (short)Integer.parseInt(birthday[0]);
		stuIn.stPersonInfoEx.byMonth = (byte)Integer.parseInt(birthday[1]);
		stuIn.stPersonInfoEx.byDay = (byte)Integer.parseInt(birthday[2]);
		
		// 性别,1-男,2-女,作为查询条件时,此参数填0,则表示此参数无效
		byte bySex = 1;
		stuIn.stPersonInfoEx.bySex = bySex;	
		
		// 人员名字	
		String personName = "张生";
		try {
			System.arraycopy(personName.getBytes(encode), 0, stuIn.stPersonInfoEx.szPersonName, 0, personName.getBytes(encode).length);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} 
		
		// 证件类型,详见 EM_CERTIFICATE_TYPE
		byte byIdType = 1;
		stuIn.stPersonInfoEx.byIDType = byIdType;  
		
		// 人员唯一标识(证件号码,工号,或其他编号)
		String id ="629006200017264512";
		System.arraycopy(id.getBytes(), 0, stuIn.stPersonInfoEx.szID, 0, id.getBytes().length); 					  
		
		// 国际,符合ISO3166规范
		System.arraycopy("CN".getBytes(), 0, stuIn.stPersonInfoEx.szCountry, 0, "CN".getBytes().length); 		
		
		 // 省份
		String province = "HB";
		try {
			System.arraycopy(province.getBytes(encode), 0, stuIn.stPersonInfoEx.szProvince, 0, province.getBytes(encode).length);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}  
		
		// 城市
		String city = "WH";
		try {
			System.arraycopy(city.getBytes(encode), 0, stuIn.stPersonInfoEx.szCity, 0, city.getBytes(encode).length);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} 

		// 出参
		NET_OUT_OPERATE_FACERECONGNITIONDB stuOut = new NET_OUT_OPERATE_FACERECONGNITIONDB() ;	
		
		stuIn.write();
	    if(netsdk.CLIENT_OperateFaceRecognitionDB(m_hLoginHandle, stuIn, stuOut, 3000)) {
	    	System.out.println("修改人员信息成功!");
		} else {
			System.out.println("修改人员信息失败!"+ ToolKits.getErrorCode());
	    	return false;
	    }
	    stuIn.read();

		return true;
	}
	
	/**
	 * 删除人员信息(即删除人脸)
	 * @param groupId 人脸库ID
	 * @param sUID  人员唯一标识符
	 */
	public boolean delFaceRecognitionDB() {    
		// 入参
		NET_IN_OPERATE_FACERECONGNITIONDB stuIn  = new NET_IN_OPERATE_FACERECONGNITIONDB();
		stuIn.emOperateType = NetSDKLib.EM_OPERATE_FACERECONGNITIONDB_TYPE.NET_FACERECONGNITIONDB_DELETE;
	
		//////// 使用人员扩展信息  //////////
		stuIn.bUsePersonInfoEx = 1;	
		
		// GroupID 赋值
		String groupId ="1";
		System.arraycopy(groupId.getBytes(), 0, stuIn.stPersonInfoEx.szGroupID, 0, groupId.getBytes().length);

		// UID赋值
		String sUID ="000011692252252515025540162542";
		System.arraycopy(sUID.getBytes(), 0, stuIn.stPersonInfoEx.szUID, 0, sUID.getBytes().length);

		// 出参
		NET_OUT_OPERATE_FACERECONGNITIONDB stuOut = new NET_OUT_OPERATE_FACERECONGNITIONDB() ;	

	    if(netsdk.CLIENT_OperateFaceRecognitionDB(m_hLoginHandle, stuIn, stuOut, 3000)) {
	    	System.out.println("删除人员信息成功!");
		} else {
			System.out.println("删除人员信息失败!"+ ToolKits.getErrorCode());
	    	return false;
	    }	    
		return true;
	}
	
	/**
	 * 通过UID删除人员信息和人脸样本
	 * @param sUID  人员唯一标识符
	 */
	public boolean delFaceRecognitionDBByUID() {    		
		String[] UIDS = {"000011692252252515025540162542"};
		// 入参
		NET_IN_OPERATE_FACERECONGNITIONDB stuIn  = new NET_IN_OPERATE_FACERECONGNITIONDB();
		stuIn.emOperateType = NetSDKLib.EM_OPERATE_FACERECONGNITIONDB_TYPE.NET_FACERECONGNITIONDB_DELETE_BY_UID;
		//添加的UID个数 
		int nMaxNum = UIDS.length;
		// 先初始化用户信息数组
		NET_UID_CHAR[] uidArr = new NET_UID_CHAR[nMaxNum];
		for (int i = 0; i < nMaxNum; i++) {
			uidArr[i] = new NET_UID_CHAR();
		}		
		// UID赋值
		for (int i = 0; i < nMaxNum; i++) {
			System.arraycopy(UIDS[i].getBytes(), 0,uidArr[i].szUID, 0, UIDS[i].getBytes().length);
		}
		stuIn.nUIDNum = nMaxNum;
		stuIn.stuUIDs = new Memory(uidArr[0].size() * nMaxNum); // 申请内存
		stuIn.stuUIDs.clear(uidArr[0].size() * nMaxNum);
		// 将用户信息传给指针
		ToolKits.SetStructArrToPointerData(uidArr, stuIn.stuUIDs);		

		// 出参
		NET_OUT_OPERATE_FACERECONGNITIONDB stuOut = new NET_OUT_OPERATE_FACERECONGNITIONDB() ;	

	    if(netsdk.CLIENT_OperateFaceRecognitionDB(m_hLoginHandle, stuIn, stuOut, 3000)) {
	    	System.out.println("删除人员信息成功!");
		} else {
			System.out.println("删除人员信息失败!"+ToolKits.getErrorCode());
	    	return false;
	    }	 
	    System.out.println("错误码个数: "+stuOut.nErrorCodeNum);
		return true;
	}
	
	
	
	/**
	 * 以人脸库的角度进行布控
	 * @param groupId 人脸库ID
	 */
	public boolean putFaceRecognitionDisposition() {
		// 入参
		NET_IN_FACE_RECOGNITION_PUT_DISPOSITION_INFO stIn = new NET_IN_FACE_RECOGNITION_PUT_DISPOSITION_INFO();
		// 人脸库ID
		String groupId = "3";
		System.arraycopy(groupId.getBytes(), 0, stIn.szGroupId, 0, groupId.getBytes().length);
		// 布控视频通道个数	
		stIn.nDispositionChnNum = 1;		
		stIn.stuDispositionChnInfo[0].nSimilary = 80;
		stIn.stuDispositionChnInfo[0].nChannelID = 6;
		
		// 出参
		NET_OUT_FACE_RECOGNITION_PUT_DISPOSITION_INFO stOut = new NET_OUT_FACE_RECOGNITION_PUT_DISPOSITION_INFO();
		
		if(netsdk.CLIENT_FaceRecognitionPutDisposition(m_hLoginHandle, stIn, stOut, 4000)) {
           System.out.println("通道布控结果个数:" + stOut.nReportCnt);			
		   for(int i = 0; i < stOut.nReportCnt; i++) {
			   if(stOut.bReport[i] == 1) {
						System.out.println("通道布控结果 : 成功。");
				} else {
						System.err.println("通道布控结果 : 失败。");			
			   }
		   }	
		} else {
			return false;
		}
		return true;
	}
	
	/**
	 * 以人脸库的角度进行撤控
	 * @param groupId 人脸库ID
	 */
	public boolean delFaceRecognitionDisposition() {
		// 入参
		NET_IN_FACE_RECOGNITION_DEL_DISPOSITION_INFO stIn = new NET_IN_FACE_RECOGNITION_DEL_DISPOSITION_INFO();
		// 人脸库ID
		String groupId = "1";
		System.arraycopy(groupId.getBytes(), 0, stIn.szGroupId, 0, groupId.getBytes().length);
		
		// 撤控视频通道个数
		stIn.nDispositionChnNum = 1; 
		stIn.nDispositionChn[0] = 6;
		
		// 出参
		NET_OUT_FACE_RECOGNITION_DEL_DISPOSITION_INFO stOut = new NET_OUT_FACE_RECOGNITION_DEL_DISPOSITION_INFO();
		
		if( netsdk.CLIENT_FaceRecognitionDelDisposition(m_hLoginHandle, stIn, stOut, 4000)) {
			System.out.println("通道撤控结果个数:" + stOut.nReportCnt);			
			for(int i = 0; i < stOut.nReportCnt; i++) {
				if(stOut.bReport[i] == 1) {
					System.out.println("通道撤控结果 : 成功。");
				} else {
					System.err.println("通道撤控结果 : 失败。");
				}
			}
		} else {
			return false;
		}
		return true;
	}
	
	/**
	 * 订阅检测结果
	 */
	public void attachDetectMultiFaceState() {
		// 获取检测Token
		faceRServerGetDetectToken();
		// 入参
		NET_IN_MULTIFACE_DETECT_STATE pstInParam = new NET_IN_MULTIFACE_DETECT_STATE();
		pstInParam.nTokensNum = 1;
		pstInParam.nTokens[0] = nToken; // 查询令牌
		pstInParam.cbMultiFaceDetectState = MultiFaceDetectState.getInstance();
		pstInParam.write();
		// 出参
		NET_OUT_MULTIFACE_DETECT_STATE pstOutParam = new NET_OUT_MULTIFACE_DETECT_STATE();
		pstOutParam.write();
		attachFaceHandle = netsdk.CLIENT_AttachDetectMultiFaceState(m_hLoginHandle, pstInParam.getPointer(),
				pstOutParam.getPointer(), 4000);
		pstInParam.read();
		pstOutParam.read();
		if (attachFaceHandle.longValue() != 0) {
			System.out.println("AttachFaceFindState Succeed!");
		} else {
			System.out.println("AttachFaceFindState Failed, Error:" + ToolKits.getErrorCode());
		}
	}

	private static class MultiFaceDetectState implements NetSDKLib.fMultiFaceDetectState {
		private static MultiFaceDetectState instance;

		public static MultiFaceDetectState getInstance() {
			if (instance == null) {
				instance = new MultiFaceDetectState();
			}
			return instance;
		}

		@Override
		public void invoke(LLong lAttachHandle, Pointer pstStates, Pointer dwUser) {
			NET_CB_MULTIFACE_DETECT_STATE msg = new NET_CB_MULTIFACE_DETECT_STATE();
			ToolKits.GetPointerData(pstStates, msg);
			System.out.println("检测进度: " + msg.nProgress);
			System.out.println("大图ID: " + msg.stuImageRelation.nBigPicId);
			System.out.println("大图中小图张数: " + msg.stuImageRelation.nSmallPicNum);
			NET_SMALL_PIC_INFO[] stuSmallPicInfo = msg.stuImageRelation.stuSmallPicInfo;
			for (int i = 0; i < msg.stuImageRelation.nSmallPicNum; i++) {
				System.out.println("第" + (i + 1) + "张小图-------");
				System.out.println("小图ID: " + stuSmallPicInfo[i].nSmallPicId);
				System.out.println("目标类型: " + stuSmallPicInfo[i].emDetectObjType);
				System.out.println("小图在大图中的位置: " + stuSmallPicInfo[i].stuRect.toString());
			}
			System.out.println(
					"大图检测小图结果错误码: " + EM_MULTIFACE_DETECT_ERRCODE.getNoteByValue(msg.stuImageRelation.emDetectErrCode));
		}

	}

	/**
	 * 上传图片进行检测
	 */
	public void faceRecognitionDetectMultiFace() {
		NET_IN_FACE_RECOGNITION_DETECT_MULTI_FACE_INFO stIn = new NET_IN_FACE_RECOGNITION_DETECT_MULTI_FACE_INFO();
		String picPath = "D:\\297.jpg";
		byte[] picBuf = ToolKits.readPictureToByteArray(picPath);
		stIn.bBigPicInfoExEnable = 1;
		//stIn.emDetectObjType = NetSDKLib.EM_OBJECT_TYPE.EM_OBJECT_TYPE_VECHILE;// 目标类型 -机动车
		stIn.emDetectObjType = NetSDKLib.EM_OBJECT_TYPE.EM_OBJECT_TYPE_FACE;// 目标类型-人脸
		stIn.nBigPicNumEx = 1;
		stIn.stuBigPicInfoEx[0].dwOffSet = 0;
		//stIn.stuBigPicInfoEx[0].emObjectType = EM_DETECT_OBJECT_TYPE.EM_DETECT_OBJECT_TYPE_VEHICLE.getValue();// 目标类型-机动车
		stIn.stuBigPicInfoEx[0].emObjectType = EM_DETECT_OBJECT_TYPE.EM_DETECT_OBJECT_TYPE_FACE.getValue();// 目标类型-人脸
		stIn.stuBigPicInfoEx[0].dwFileLenth = picBuf.length;
		stIn.stuBigPicInfoEx[0].nPicID = 666;// 大图ID,设置为唯一值
		stIn.nBufferLen = picBuf.length;
		stIn.pBuffer = new Memory(picBuf.length);
		stIn.pBuffer.write(0, picBuf, 0, picBuf.length);
		stIn.nToken = nToken;

		NET_OUT_FACE_RECOGNITION_DETECT_MULTI_FACE_INFO stOut = new NET_OUT_FACE_RECOGNITION_DETECT_MULTI_FACE_INFO();
		stIn.write();
		stOut.write();
		boolean bRet = netsdk.CLIENT_FaceRecognitionDetectMultiFace(m_hLoginHandle, stIn.getPointer(),
				stOut.getPointer(), 3000);
		stIn.read();
		stOut.read();
		if (bRet) {
			System.out.println("CLIENT_FaceRecognitionDetectMultiFace success");
		} else {
			System.out.println("CLIENT_FaceRecognitionDetectMultiFace failed");
			System.out.println("error = " + ToolKits.getErrorCode());
		}
	}

	/**
	 * 取消订阅
	 */
	public void detachDetectMultiFaceState() {
		if (attachFaceHandle.longValue() != 0) {
			netsdk.CLIENT_DetachDetectMultiFaceState(attachFaceHandle);
		}
	}
	
    private final AnalyseTaskModule analyseTaskModule = new AnalyseTaskModule(netsdk);
    /**
     * 1:1,图片比对
     */
    public void matchPicture() {
        try {
            int result = analyseTaskModule.matchImage(m_hLoginHandle.longValue(), new FileInputStream(new File("D:/296.jpg")), new FileInputStream(new File("D:/测试图片/1.jpg")), 3000);
            System.out.println(result);
        } catch (IOException e) {
            e.printStackTrace();
        }
     }

	

	public class IntPoint extends NetSDKLib.SdkStructure {

		public int value;

		public IntPoint() {
		}

		public IntPoint(int value) {
			this.value = value;
		}
	}
	/**
	 * 机动车以图搜图
	 */
	public void searchByVechilePictureMultiVer() {
		searchByVechilePictureEx("2023-01-01", "2023-04-20", "50");
	}

	/**
	 * 机动车以图搜图
	 * 
	 * @param startTime 开始时间
	 * @param endTime   结束时间
	 * @param chn       通道号
	 * @param similary  相似度
	 * @param memory    图片缓存
	 * @param nPicLen   图片大小
	 */
	public void searchByVechilePictureEx(String startTime, String endTime, String similary) {
		String[] startTimeStr = startTime.split("-");
		String[] endTimeStr = endTime.split("-");
		NET_IN_STARTMULTIFIND_FACERECONGNITION_EX stInStartFind = new NET_IN_STARTMULTIFIND_FACERECONGNITION_EX();
		// 通道号
		stInStartFind.nChannelCount = 4;
		IntPoint[] intPoints = new IntPoint[4];
		for (int i = 0; i < 4; i++) {
			intPoints[i] = new IntPoint(i);
		}
		stInStartFind.pChannelID = new Memory(intPoints[0].size() * stInStartFind.nChannelCount);
		stInStartFind.pChannelID.clear(intPoints[0].size() * stInStartFind.nChannelCount);
		ToolKits.SetStructArrToPointerData(intPoints, stInStartFind.pChannelID);
		stInStartFind.emObjectType = NetSDKLib.EM_OBJECT_TYPE.EM_OBJECT_TYPE_VECHILE;
		// 相似度
		if (!similary.equals("")) {
			stInStartFind.stMatchOptions.nSimilarity = Integer.parseInt(similary);//相似度
			stInStartFind.stMatchOptions.nMaxCandidate = 1000;//报告的最大候选个数(根据相似度进行排序,取相似度最大的候选人数报告)
		}

		stInStartFind.stFilterInfo.nGroupIdNum = 0;
		stInStartFind.stFilterInfo.nRangeNum = 1;
		stInStartFind.stFilterInfo.szRange[0] = NetSDKLib.EM_FACE_DB_TYPE.NET_FACE_DB_TYPE_HISTORY; // 历史数据库
		stInStartFind.stFilterInfo.stStartTime.dwYear = Integer.parseInt(startTimeStr[0]);
		stInStartFind.stFilterInfo.stStartTime.dwMonth = Integer.parseInt(startTimeStr[1]);
		stInStartFind.stFilterInfo.stStartTime.dwDay = Integer.parseInt(startTimeStr[2]);
		stInStartFind.stFilterInfo.stEndTime.dwYear = Integer.parseInt(endTimeStr[0]);
		stInStartFind.stFilterInfo.stEndTime.dwMonth = Integer.parseInt(endTimeStr[1]);
		stInStartFind.stFilterInfo.stEndTime.dwDay = Integer.parseInt(endTimeStr[2]);

		// 图片信息
		String picPath = "D:\\297.jpg";
		byte[] picBuf = ToolKits.readPictureToByteArray(picPath);
		stInStartFind.pBuffer = new Memory(picBuf.length);
		stInStartFind.pBuffer.write(0, picBuf, 0, picBuf.length);
		stInStartFind.nBufferLen = picBuf.length;
		stInStartFind.bPersonEx2Enable = 1; // 人员信息查询条件是否有效, 并使用扩展结构体
		stInStartFind.stPersonInfoEx2.bPersonExEnable = 0;

		stInStartFind.stPersonInfoEx2.nFacePicNumEx = 1;
		stInStartFind.stPersonInfoEx2.stuFacePicInfoEx[0].dwOffSet = 0;
		stInStartFind.stPersonInfoEx2.stuFacePicInfoEx[0].dwFileLenth = picBuf.length;

		stInStartFind.stPersonInfoEx2.nBoundingBoxNum = 1;// 大图内小图坐标信息
		stInStartFind.stPersonInfoEx2.stuBoundingBox[0].nTop = 174;
		stInStartFind.stPersonInfoEx2.stuBoundingBox[0].nLeft = 1706;
		stInStartFind.stPersonInfoEx2.stuBoundingBox[0].nRight = 4040;
		stInStartFind.stPersonInfoEx2.stuBoundingBox[0].nBottom = 4573;
		stInStartFind.stPersonInfoEx2.nTrafficCarAttributeNum = 1;// 车辆过滤信息
		stInStartFind.stPersonInfoEx2.stuTrafficCarAttribute[0].nCategoryArrayNums = 1;
		stInStartFind.stPersonInfoEx2.stuTrafficCarAttribute[0].emCategoryArray[0] = NetSDKLib.EM_NET_VEHICLE_TYPE.NET_VEHICLE_TYPE_MICROBUS;// 面包车
		stInStartFind.stPersonInfoEx2.stuTrafficCarAttribute[0].nAnnualInspection = 2;//是否有年检标, 0: 不限  1: 无  2: 有
		stInStartFind.stPersonInfoEx2.stuTrafficCarAttribute[0].nVehicleColorArrayNums = 1;
		stInStartFind.stPersonInfoEx2.stuTrafficCarAttribute[0].emVehicleColorArray[0] = EM_OBJECT_COLOR_TYPE.EM_OBJECT_COLOR_TYPE_WHITE;
		// 让设备根据查询条件整理结果集
		NET_OUT_STARTMULTIFIND_FACERECONGNITION_EX stOutParam = new NET_OUT_STARTMULTIFIND_FACERECONGNITION_EX();
		stInStartFind.write();
		stOutParam.write();
		if (netsdk.CLIENT_StartMultiFindFaceRecognitionEx(m_hLoginHandle, stInStartFind.getPointer(),
				stOutParam.getPointer(), 3000)) {
			stOutParam.read();
			System.out.println("CLIENT_StartMultiFindFaceRecognitionEx success, count = " + stOutParam.nTotalCount);
			NetSDKLib.LLong findHandle = stOutParam.lFindHandle;
			if (stOutParam.nTotalCount == -1) { // -1表示总条数未生成,要推迟获取, 使用CLIENT_AttachFaceFindState接口状态
				nToken = stOutParam.nToken;
				// 入参
				NetSDKLib.NET_IN_FACE_FIND_STATE pstInParam = new NetSDKLib.NET_IN_FACE_FIND_STATE();
				pstInParam.nTokenNum = 1;
				pstInParam.nTokens = new IntByReference(nToken); // 查询令牌
				pstInParam.cbFaceFindState = DefaultFaceFindStateCallback.getInstance();

				// 出参
				NetSDKLib.NET_OUT_FACE_FIND_STATE pstOutParam = new NetSDKLib.NET_OUT_FACE_FIND_STATE();
				pstInParam.write();
				NetSDKLib.LLong attachFaceHandle = netsdk.CLIENT_AttachFaceFindState(m_hLoginHandle, pstInParam,
						pstOutParam, 4000);
				pstInParam.read();
				if (attachFaceHandle.longValue() != 0) {
					System.out.println("AttachFaceFindState Succeed!");
				}
				// 等待进度完成
				try {
					while (DefaultFaceFindStateCallback.getInstance().getProgress(m_hLoginHandle.longValue(),
							attachFaceHandle.longValue(), nToken) < 100) {
					}
					// 进度到100，有数据了默认查个10条
					doFindSearchByVechilePictureEx(findHandle, 10, 10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else {
				doFindSearchByVechilePictureEx(findHandle,10,stOutParam.nTotalCount);
			}
		} else {
			System.out.println("CLIENT_StartMultiFindFaceRecognitionEx Failed, Error:" + ToolKits.getErrorCode());
		}
	}
	
		
	/**
	 *  机动车以图搜图
	 * @param longHandle CLIENT_StartFindFaceRecognition 接口返回的查询句柄
	 * @param count      查询的个数
	 */
	public void doFindSearchByVechilePictureEx(NetSDKLib.LLong findHandle, int count,int nTotalCount) {
		int doNextCount = 0;
		// 分页查找数据
		NET_IN_DOFIND_FACERECONGNITION_EX stFindIn = new NET_IN_DOFIND_FACERECONGNITION_EX();
		stFindIn.lFindHandle = findHandle;
		stFindIn.nCount = 10; // 当前想查询的记录条数
		stFindIn.nBeginNum = 0; // 每次递增
		int index =0;
		NET_OUT_DOFIND_FACERECONGNITION_EX stFindOut = new NET_OUT_DOFIND_FACERECONGNITION_EX();
		stFindOut.nCadidateEx2Num = count;

		NET_CANDIDATE_INFOEX2[] tmp = new NET_CANDIDATE_INFOEX2[count];
		for (int i = 0; i < count; i++) {
			tmp[i] = new NET_CANDIDATE_INFOEX2();
		}
		stFindOut.nBufferLen = tmp[0].size() * count;
		stFindOut.pBuffer = new Memory(tmp[0].size() * count);
		stFindOut.pBuffer.clear(tmp[0].size() * count);
		for (int i = 0; i < count; i++) {
			tmp[i].stuCandidatesEx.stPersonInfo.szFacePicInfo[0].nFilePathLen = 256;
			tmp[i].stuCandidatesEx.stPersonInfo.szFacePicInfo[0].pszFilePath = new Memory(256);
		}
		stFindOut.pstuCandidatesEx2 = new Memory(tmp[0].size() * count); // Pointer初始化
		stFindOut.pstuCandidatesEx2.clear(tmp[0].size() * count);

		ToolKits.SetStructArrToPointerData(tmp, stFindOut.pstuCandidatesEx2); // 将数组内存拷贝给 Pointer

		do {
			stFindIn.write();
			stFindOut.write();
			if (netsdk.CLIENT_DoFindFaceRecognitionEx(stFindIn.getPointer(), stFindOut.getPointer(), 1000)) {
				System.out.println("CLIENT_DoFindFaceRecognitionEx Succeed");
				stFindOut.read();
				ToolKits.GetPointerDataToStructArr(stFindOut.pstuCandidatesEx2, tmp);
				System.out.println("设备实际返回的候选信息结构体个数: " + stFindOut.nRetCadidateEx2Num);
				if (stFindOut.nRetCadidateEx2Num == 0) {
					System.out.println("没有查询到相关数据");
					break;
				}
				try {
					for (int i = 0; i < stFindOut.nRetCadidateEx2Num; i++) {
						index = i + doNextCount * count; // 查询的总个数 - 1, 从0开始							
						System.out.println("szVehicleColor: "+ new String(tmp[i].stuHistoryTrafficCarInfo.szVehicleColor, encode));
						System.out.println("szPlateNumber: " + new String(tmp[i].stuHistoryTrafficCarInfo.szPlateNumber, encode));

				    }
						
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			} else {
				System.out.println("CLIENT_DoFindFaceRecognitionEx Failed, Error:" + ENUMERROR.getErrorMessage());
				break;
			}

			if (stFindOut.nRetCadidateEx2Num < stFindIn.nCount|| index == (nTotalCount-1)) {
				System.out.println("没有更多数据,结束查询");
				break;
			} else {
				stFindIn.nBeginNum += count;
				doNextCount++;
			}
		} while (true);
		netsdk.CLIENT_StopFindFaceRecognition(findHandle);
	}
	

	/**
	 * 人脸以图搜图（注册库）
	 */
	public void searchByFacePictureBlockListMultiVer() {
		searchByFacePictureBlockList("2023-08-17", "2023-08-18", "50");
	}

	/**
	 * 人脸以图搜图（注册库）
	 * 
	 * @param startTime 开始时间
	 * @param endTime   结束时间
	 * @param chn       通道号
	 * @param similary  相似度
	 * @param memory    图片缓存
	 * @param nPicLen   图片大小
	 */
	public void searchByFacePictureBlockList(String startTime, String endTime,  String similary) {
		String[] startTimeStr = startTime.split("-");
		String[] endTimeStr = endTime.split("-");
		NET_IN_STARTMULTIFIND_FACERECONGNITION_EX stInStartFind = new NET_IN_STARTMULTIFIND_FACERECONGNITION_EX();
			
		stInStartFind.emObjectType = NetSDKLib.EM_OBJECT_TYPE.EM_OBJECT_TYPE_FACE;
		// 相似度
		if (!similary.equals("")) {
			stInStartFind.stMatchOptions.nSimilarity = Integer.parseInt(similary);//相似度
			stInStartFind.stMatchOptions.nMaxCandidate = 1000;//报告的最大候选个数(根据相似度进行排序,取相似度最大的候选人数报告)
		}
		
		stInStartFind.stFilterInfo.nGroupIdNum = 1;
		String nGroupId = "3";
		System.arraycopy(nGroupId.getBytes(), 0, stInStartFind.stFilterInfo.szGroupIdArr[0].szGroupId, 0, nGroupId.getBytes().length);
		stInStartFind.stFilterInfo.nRangeNum = 1;
		stInStartFind.stFilterInfo.szRange[0] = NetSDKLib.EM_FACE_DB_TYPE.NET_FACE_DB_TYPE_BLACKLIST; // 禁止名单数据库(现在用作注册库)
		stInStartFind.stFilterInfo.stStartTime.dwYear = Integer.parseInt(startTimeStr[0]);
		stInStartFind.stFilterInfo.stStartTime.dwMonth = Integer.parseInt(startTimeStr[1]);
		stInStartFind.stFilterInfo.stStartTime.dwDay = Integer.parseInt(startTimeStr[2]);
		stInStartFind.stFilterInfo.stEndTime.dwYear = Integer.parseInt(endTimeStr[0]);
		stInStartFind.stFilterInfo.stEndTime.dwMonth = Integer.parseInt(endTimeStr[1]);
		stInStartFind.stFilterInfo.stEndTime.dwDay = Integer.parseInt(endTimeStr[2]);

		// 图片信息
		String picPath = "D:\\297.jpg";
		byte[] picBuf = ToolKits.readPictureToByteArray(picPath);
		stInStartFind.bPersonEx2Enable = 1; // 人员信息查询条件是否有效, 并使用扩展结构体
		stInStartFind.stPersonInfoEx2.bPersonExEnable = 1;
		stInStartFind.stPersonInfoEx2.stPersonInfoEx.wFacePicNum = 1;
		stInStartFind.stPersonInfoEx2.stPersonInfoEx.szFacePicInfo[0].dwOffSet = 0;
		stInStartFind.stPersonInfoEx2.stPersonInfoEx.szFacePicInfo[0].dwFileLenth = picBuf.length;
		stInStartFind.pBuffer = new Memory(picBuf.length);
		stInStartFind.pBuffer.write(0, picBuf, 0, picBuf.length);
		stInStartFind.nBufferLen = picBuf.length;

		// 让设备根据查询条件整理结果集
		NET_OUT_STARTMULTIFIND_FACERECONGNITION_EX stOutParam = new NET_OUT_STARTMULTIFIND_FACERECONGNITION_EX();
		stInStartFind.write();
		stOutParam.write();
		if (netsdk.CLIENT_StartMultiFindFaceRecognitionEx(m_hLoginHandle, stInStartFind.getPointer(),
				stOutParam.getPointer(), 3000)) {
			stOutParam.read();
			System.out.println("CLIENT_StartMultiFindFaceRecognitionEx success, count = " + stOutParam.nTotalCount);
			NetSDKLib.LLong findHandle = stOutParam.lFindHandle;
			if (stOutParam.nTotalCount == -1) { // -1表示总条数未生成,要推迟获取, 使用CLIENT_AttachFaceFindState接口状态
				nToken = stOutParam.nToken;
				// 入参
				NetSDKLib.NET_IN_FACE_FIND_STATE pstInParam = new NetSDKLib.NET_IN_FACE_FIND_STATE();
				pstInParam.nTokenNum = 1;
				pstInParam.nTokens = new IntByReference(nToken); // 查询令牌
				pstInParam.cbFaceFindState = DefaultFaceFindStateCallback.getInstance();

				// 出参
				NetSDKLib.NET_OUT_FACE_FIND_STATE pstOutParam = new NetSDKLib.NET_OUT_FACE_FIND_STATE();
				pstInParam.write();
				NetSDKLib.LLong attachFaceHandle = netsdk.CLIENT_AttachFaceFindState(m_hLoginHandle, pstInParam,
						pstOutParam, 4000);
				pstInParam.read();
				if (attachFaceHandle.longValue() != 0) {
					System.out.println("AttachFaceFindState Succeed!");
				}
				// 等待进度完成
				try {
					while (DefaultFaceFindStateCallback.getInstance().getProgress(m_hLoginHandle.longValue(),
							attachFaceHandle.longValue(), nToken) < 100) {
					}
					// 进度到100,有数据了默认查个10条
					doFindSearchByFacePictureBlockList(findHandle, 10, 10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else {
				//查询已有的所有
				doFindSearchByFacePictureBlockList(findHandle, 10,stOutParam.nTotalCount);
			}
		} else {
			System.out.println("CLIENT_StartMultiFindFaceRecognitionEx Failed, Error:" + ToolKits.getErrorCode());
		}
	}
	
		
	/**
	 *  人脸以图搜图（注册库）
	 * @param longHandle CLIENT_StartFindFaceRecognition 接口返回的查询句柄
	 * @param count      查询的个数
	 */
	public void doFindSearchByFacePictureBlockList(NetSDKLib.LLong findHandle, int count,int nTotalCount) {
		int doNextCount = 0;
		// 分页查找数据
		NET_IN_DOFIND_FACERECONGNITION_EX stFindIn = new NET_IN_DOFIND_FACERECONGNITION_EX();
		stFindIn.lFindHandle = findHandle;
		stFindIn.emDataType = EM_NEEDED_PIC_RETURN_TYPE.EM_NEEDED_PIC_TYPE_HTTP_URL.getType();
		stFindIn.nCount = 10; // 当前想查询的记录条数
		stFindIn.nBeginNum = 0; // 每次递增
		int index = 0; //总计

		NET_OUT_DOFIND_FACERECONGNITION_EX stFindOut = new NET_OUT_DOFIND_FACERECONGNITION_EX();
		stFindOut.nCadidateEx2Num = count;

		NET_CANDIDATE_INFOEX2[] tmp = new NET_CANDIDATE_INFOEX2[count];
		for (int i = 0; i < count; i++) {
			tmp[i] = new NET_CANDIDATE_INFOEX2();
		}
		stFindOut.nBufferLen = tmp[0].size() * count;
		stFindOut.pBuffer = new Memory(tmp[0].size() * count);
		stFindOut.pBuffer.clear(tmp[0].size() * count);
		for (int i = 0; i < count; i++) {
			tmp[i].stuCandidatesEx.stPersonInfo.szFacePicInfo[0].nFilePathLen = 256;
			tmp[i].stuCandidatesEx.stPersonInfo.szFacePicInfo[0].pszFilePath = new Memory(256);
		}
		stFindOut.pstuCandidatesEx2 = new Memory(tmp[0].size() * count); // Pointer初始化
		stFindOut.pstuCandidatesEx2.clear(tmp[0].size() * count);

		ToolKits.SetStructArrToPointerData(tmp, stFindOut.pstuCandidatesEx2); // 将数组内存拷贝给 Pointer

		do {
			
			stFindIn.write();
			stFindOut.write();
			if (netsdk.CLIENT_DoFindFaceRecognitionEx(stFindIn.getPointer(), stFindOut.getPointer(), 1000)) {
				System.out.println("CLIENT_DoFindFaceRecognitionEx Succeed");
				stFindOut.read();
				ToolKits.GetPointerDataToStructArr(stFindOut.pstuCandidatesEx2, tmp);
				System.out.println("设备实际返回的候选信息结构体个数: " + stFindOut.nRetCadidateEx2Num);
				if (stFindOut.nRetCadidateEx2Num == 0) {
					System.out.println("没有查询到相关数据");
					break;
				}
				try {
					for (int i = 0; i < stFindOut.nRetCadidateEx2Num; i++) {
						index = i + doNextCount * count; // 查询的总个数 - 1, 从0开始		
						//System.out.println("index: "+index);
						System.out.println("姓名: "+ new String(tmp[i].stuCandidatesEx.stPersonInfo.szPersonName, encode));
						System.out.println("性别: " +tmp[i].stuCandidatesEx.stPersonInfo.bySex);
						System.out.println("PicURL: " +tmp[i].stuCandidatesEx.stPersonInfo.szFacePicInfo[0].pszFilePath.getString(0));
				    }
						
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			} else {
				System.out.println("CLIENT_DoFindFaceRecognitionEx Failed, Error:" + ENUMERROR.getErrorMessage());
				break;
			}

			if (stFindOut.nRetCadidateEx2Num < stFindIn.nCount || index == (nTotalCount-1)) {
				System.out.println("没有更多数据,结束查询");
				break;
			} else {
				stFindIn.nBeginNum += count;
				System.out.println("stFindIn.nBeginNum: "+stFindIn.nBeginNum);
				doNextCount++;
			}
		} while (true);
		netsdk.CLIENT_StopFindFaceRecognition(findHandle);
	}

	/**
	 * 人脸以图搜图（抓拍库）
	 */
	public void searchByFacePictureHistoryMultiVer() {
		searchByFacePictureHistory("2023-08-17", "2023-08-18", "50");
	}

	/**
	 * 人脸以图搜图（抓拍库）
	 * 
	 * @param startTime 开始时间
	 * @param endTime   结束时间
	 * @param chn       通道号
	 * @param similary  相似度
	 * @param memory    图片缓存
	 * @param nPicLen   图片大小
	 */
	public void searchByFacePictureHistory(String startTime, String endTime,  String similary) {
		String[] startTimeStr = startTime.split("-");
		String[] endTimeStr = endTime.split("-");
		NET_IN_STARTMULTIFIND_FACERECONGNITION_EX stInStartFind = new NET_IN_STARTMULTIFIND_FACERECONGNITION_EX();
			
		// 通道号
		stInStartFind.nChannelCount = 4;
		IntPoint[] intPoints = new IntPoint[4];
		for (int i = 0; i < 4; i++) {
			intPoints[i] = new IntPoint(i);
		}
		stInStartFind.pChannelID = new Memory(intPoints[0].size() * stInStartFind.nChannelCount);
		stInStartFind.pChannelID.clear(intPoints[0].size() * stInStartFind.nChannelCount);
		ToolKits.SetStructArrToPointerData(intPoints, stInStartFind.pChannelID);
		stInStartFind.emObjectType = NetSDKLib.EM_OBJECT_TYPE.EM_OBJECT_TYPE_FACE;
		// 相似度
		if (!similary.equals("")) {
			stInStartFind.stMatchOptions.nSimilarity = Integer.parseInt(similary);//相似度
			stInStartFind.stMatchOptions.nMaxCandidate = 1000;//报告的最大候选个数(根据相似度进行排序,取相似度最大的候选人数报告)
		}
		
		stInStartFind.stFilterInfo.nRangeNum = 1;
		stInStartFind.stFilterInfo.szRange[0] = NetSDKLib.EM_FACE_DB_TYPE.NET_FACE_DB_TYPE_HISTORY; // 历史数据库
		stInStartFind.stFilterInfo.stStartTime.dwYear = Integer.parseInt(startTimeStr[0]);
		stInStartFind.stFilterInfo.stStartTime.dwMonth = Integer.parseInt(startTimeStr[1]);
		stInStartFind.stFilterInfo.stStartTime.dwDay = Integer.parseInt(startTimeStr[2]);
		stInStartFind.stFilterInfo.stEndTime.dwYear = Integer.parseInt(endTimeStr[0]);
		stInStartFind.stFilterInfo.stEndTime.dwMonth = Integer.parseInt(endTimeStr[1]);
		stInStartFind.stFilterInfo.stEndTime.dwDay = Integer.parseInt(endTimeStr[2]);

		// 图片信息
		String picPath = "D:\\297.jpg";
		byte[] picBuf = ToolKits.readPictureToByteArray(picPath);
		stInStartFind.bPersonEx2Enable = 1; // 人员信息查询条件是否有效, 并使用扩展结构体
		stInStartFind.stPersonInfoEx2.bPersonExEnable = 1;
		stInStartFind.stPersonInfoEx2.stPersonInfoEx.wFacePicNum = 1;
		stInStartFind.stPersonInfoEx2.stPersonInfoEx.szFacePicInfo[0].dwOffSet = 0;
		stInStartFind.stPersonInfoEx2.stPersonInfoEx.szFacePicInfo[0].dwFileLenth = picBuf.length;
		stInStartFind.pBuffer = new Memory(picBuf.length);
		stInStartFind.pBuffer.write(0, picBuf, 0, picBuf.length);
		stInStartFind.nBufferLen = picBuf.length;

		// 让设备根据查询条件整理结果集
		NET_OUT_STARTMULTIFIND_FACERECONGNITION_EX stOutParam = new NET_OUT_STARTMULTIFIND_FACERECONGNITION_EX();
		stInStartFind.write();
		stOutParam.write();
		if (netsdk.CLIENT_StartMultiFindFaceRecognitionEx(m_hLoginHandle, stInStartFind.getPointer(),
				stOutParam.getPointer(), 3000)) {
			stOutParam.read();
			System.out.println("CLIENT_StartMultiFindFaceRecognitionEx success, count = " + stOutParam.nTotalCount);
			NetSDKLib.LLong findHandle = stOutParam.lFindHandle;
			if (stOutParam.nTotalCount == -1) { // -1表示总条数未生成,要推迟获取, 使用CLIENT_AttachFaceFindState接口状态
				nToken = stOutParam.nToken;
				// 入参
				NetSDKLib.NET_IN_FACE_FIND_STATE pstInParam = new NetSDKLib.NET_IN_FACE_FIND_STATE();
				pstInParam.nTokenNum = 1;
				pstInParam.nTokens = new IntByReference(nToken); // 查询令牌
				pstInParam.cbFaceFindState = DefaultFaceFindStateCallback.getInstance();

				// 出参
				NetSDKLib.NET_OUT_FACE_FIND_STATE pstOutParam = new NetSDKLib.NET_OUT_FACE_FIND_STATE();
				pstInParam.write();
				NetSDKLib.LLong attachFaceHandle = netsdk.CLIENT_AttachFaceFindState(m_hLoginHandle, pstInParam,
						pstOutParam, 4000);
				pstInParam.read();
				if (attachFaceHandle.longValue() != 0) {
					System.out.println("AttachFaceFindState Succeed!");
				}
				// 等待进度完成
				try {
					while (DefaultFaceFindStateCallback.getInstance().getProgress(m_hLoginHandle.longValue(),
							attachFaceHandle.longValue(), nToken) < 100) {
					}
					// 进度到100,有数据了默认查个10条
					doFindSearchByFacePictureHistory(findHandle, 10, 10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else {
				//查询已有的所有
				doFindSearchByFacePictureHistory(findHandle, 10,stOutParam.nTotalCount);
			}
		} else {
			System.out.println("CLIENT_StartMultiFindFaceRecognitionEx Failed, Error:" + ToolKits.getErrorCode());
		}
	}
	
		
	/**
	 *  人脸以图搜图（抓拍库）
	 * @param longHandle CLIENT_StartFindFaceRecognition 接口返回的查询句柄
	 * @param count      查询的个数
	 */
	public void doFindSearchByFacePictureHistory(NetSDKLib.LLong findHandle, int count,int nTotalCount) {
		int doNextCount = 0;
		// 分页查找数据
		NET_IN_DOFIND_FACERECONGNITION_EX stFindIn = new NET_IN_DOFIND_FACERECONGNITION_EX();
		stFindIn.lFindHandle = findHandle;
		stFindIn.emDataType = EM_NEEDED_PIC_RETURN_TYPE.EM_NEEDED_PIC_TYPE_HTTP_URL.getType();
		stFindIn.nCount = 10; // 当前想查询的记录条数
		stFindIn.nBeginNum = 0; // 每次递增
		int index = 0; //总计

		NET_OUT_DOFIND_FACERECONGNITION_EX stFindOut = new NET_OUT_DOFIND_FACERECONGNITION_EX();
		stFindOut.nCadidateEx2Num = count;

		NET_CANDIDATE_INFOEX2[] tmp = new NET_CANDIDATE_INFOEX2[count];
		for (int i = 0; i < count; i++) {
			tmp[i] = new NET_CANDIDATE_INFOEX2();
		}
		stFindOut.nBufferLen = tmp[0].size() * count;
		stFindOut.pBuffer = new Memory(tmp[0].size() * count);
		stFindOut.pBuffer.clear(tmp[0].size() * count);
		for (int i = 0; i < count; i++) {
			tmp[i].stuCandidatesEx.stPersonInfo.szFacePicInfo[0].nFilePathLen = 256;
			tmp[i].stuCandidatesEx.stPersonInfo.szFacePicInfo[0].pszFilePath = new Memory(256);
		}
		stFindOut.pstuCandidatesEx2 = new Memory(tmp[0].size() * count); // Pointer初始化
		stFindOut.pstuCandidatesEx2.clear(tmp[0].size() * count);

		ToolKits.SetStructArrToPointerData(tmp, stFindOut.pstuCandidatesEx2); // 将数组内存拷贝给 Pointer

		do {
			
			stFindIn.write();
			stFindOut.write();
			if (netsdk.CLIENT_DoFindFaceRecognitionEx(stFindIn.getPointer(), stFindOut.getPointer(), 1000)) {
				System.out.println("CLIENT_DoFindFaceRecognitionEx Succeed");
				stFindOut.read();
				ToolKits.GetPointerDataToStructArr(stFindOut.pstuCandidatesEx2, tmp);
				System.out.println("设备实际返回的候选信息结构体个数: " + stFindOut.nRetCadidateEx2Num);
				if (stFindOut.nRetCadidateEx2Num == 0) {
					System.out.println("没有查询到相关数据");
					break;
				}
				try {
					for (int i = 0; i < stFindOut.nRetCadidateEx2Num; i++) {
						index = i + doNextCount * count; // 查询的总个数 - 1, 从0开始		
						//System.out.println("index: "+index);
						System.out.println("姓名: "+ new String(tmp[i].stuCandidatesEx.stPersonInfo.szPersonName, encode));
						System.out.println("性别: " +tmp[i].stuCandidatesEx.stPersonInfo.bySex);
						System.out.println("PicURL: " +tmp[i].stuCandidatesEx.stPersonInfo.szFacePicInfo[0].pszFilePath.getString(0));
				    }
						
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			} else {
				System.out.println("CLIENT_DoFindFaceRecognitionEx Failed, Error:" + ENUMERROR.getErrorMessage());
				break;
			}

			if (stFindOut.nRetCadidateEx2Num < stFindIn.nCount || index == (nTotalCount-1)) {
				System.out.println("没有更多数据,结束查询");
				break;
			} else {
				stFindIn.nBeginNum += count;
				System.out.println("stFindIn.nBeginNum: "+stFindIn.nBeginNum);
				doNextCount++;
			}
		} while (true);
		netsdk.CLIENT_StopFindFaceRecognition(findHandle);
	}
	
    
	/******************************** 测试控制台 ***************************************/

	// 配置登陆地址，端口，用户名，密码
	private String m_strIpAddr = "172.23.222.103";
	private int m_nPort = 37777;
	private String m_strUser = "admin";
	private String m_strPassword = "Admin123";

	public static void main(String[] args) {
		MC8000Demo demo = new MC8000Demo();
		demo.InitTest();
		demo.RunTest();
		demo.EndTest();

	}

	/**
	 * 初始化测试
	 */
	public void InitTest() {
		MC8000Demo.Init();
		this.loginWithHighLevel();
	}

	/**
	 * 加载测试内容
	 */
	public void RunTest() {
		CaseMenu menu = new CaseMenu();
		// 一、设备、通道信息获取
		menu.addItem(new CaseMenu.Item(this, "获取已添加的设备信息", "getAllDeviceInfo"));
		menu.addItem(new CaseMenu.Item(this, "获取设备通道信息", "getChannelInfo"));
		menu.addItem(new CaseMenu.Item(this, "设备、通道信息一起获取", "getDeviceInfoEx"));

		// 二、智能事件订阅
		menu.addItem(new CaseMenu.Item(this, "选择通道", "setChannelID"));
		menu.addItem(new CaseMenu.Item(this, "订阅智能事件", "AttachEventRealLoadPic"));
		menu.addItem(new CaseMenu.Item(this, "停止侦听智能事件", "DetachEventRealLoadPic"));

		// 三、人脸库查询
		menu.addItem(new CaseMenu.Item(this, "查询人脸库信息", "findGroupInfo"));	
		
		// 四、人脸库操作
		menu.addItem(new CaseMenu.Item(this, "添加人脸库", "addFaceRecognitionGroup"));
		menu.addItem(new CaseMenu.Item(this, "修改人脸库", "modifyFaceRecognitionGroup"));
		menu.addItem(new CaseMenu.Item(this, "删除人脸库", "deleteFaceRecognitionGroup"));
		
		// 五、人脸库成员操作
		menu.addItem(new CaseMenu.Item(this, "添加人员信息和人脸样", "addFaceRecognitionDB"));
		menu.addItem(new CaseMenu.Item(this, "修改人员信息和人脸样本", "modifyFaceRecognitionDB"));
		menu.addItem(new CaseMenu.Item(this, "删除人员信息和人脸样本", "delFaceRecognitionDB"));
		menu.addItem(new CaseMenu.Item(this, "通过UID删除人员信息和人脸样本", "delFaceRecognitionDBByUID"));
		
		// 十三、布控撤控 （前提需要设备先完成通道配置）
		menu.addItem(new CaseMenu.Item(this, "以人脸库的角度进行布控", "putFaceRecognitionDisposition"));
		menu.addItem(new CaseMenu.Item(this, "以人脸库的角度进行撤控", "delFaceRecognitionDisposition"));
																		
		// 六、 图片检测
		menu.addItem(new CaseMenu.Item(this, "订阅检测结果", "attachDetectMultiFaceState"));
		menu.addItem(new CaseMenu.Item(this, "上传图片进行检测", "faceRecognitionDetectMultiFace"));
		menu.addItem(new CaseMenu.Item(this, "取消订阅", "detachDetectMultiFaceState"));
				
		// 七、人脸1v1
		menu.addItem(new CaseMenu.Item(this, "人脸1v1", "matchPicture"));
		
		// 八、人脸以图搜图（注册库）
		menu.addItem(new CaseMenu.Item(this, "人脸以图搜图（注册库）", "searchByFacePictureBlockListMultiVer"));						
		
		// 九、人脸以图搜图（抓拍库）
		menu.addItem(new CaseMenu.Item(this, "人脸以图搜图（抓拍库）", "searchByFacePictureHistoryMultiVer"));			
		
		// 十二、机动车以图搜图
		menu.addItem(new CaseMenu.Item(this, "机动车以图搜图", "searchByVechilePictureMultiVer"));

		menu.run();
	}

	/**
	 * 结束测试
	 */
	public void EndTest() {
		System.out.println("End Test");
		this.logOut(); // 登出设备
		System.out.println("See You...");
		MC8000Demo.cleanAndExit(); // 清理资源并退出
	}
	/******************************** 结束 ***************************************/
}
